/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_sortable.h                                                         *
 ****************************************************************************/

/**
 * @file elisa_sortable.h
 * @brief Definition of sortable objects and containers
 */

/** @defgroup Sortable Sortable
 * @brief Classes for sortable objects to be added in containers.
 */


#ifndef _ELISA_SORTABLE_H
#define _ELISA_SORTABLE_H


#include <queue>
#include <set>
#include <stack>
#include "elisa_defs.h"


NAMESPACE_ELISA
/**
 * @ingroup Sortable
 * @class Sortable
 * @brief Sortable objects to be added in containers
 */
class Sortable
{
public:

	/// Constructor
	Sortable()
	{
	}

	/// Destructor
	virtual
	~Sortable()
	{
	}

	/// Objects are sorted wrt. their priorities
	virtual double priority() const
	{
		return 0.0;
	}
};



/**
 * @ingroup Sortable
 * @class SortableComparator
 * @brief Comparison of sortable objects used for set managing
 */
struct SortableComparator {
	/**
 	 * @brief compare two sortables
 	 * @return true if *s1 is strictly smaller than *s2
 	 */
	bool operator ()(const Sortable *s1,
	                 const Sortable *s2) const
	{
		if (s1 == s2) {
			return false;
		} else if (s1->priority() != s2->priority()) {
			return(s1->priority() > s2->priority());
		} else {
			return(s1 < s2);
		}
	}
};


/**
 * @ingroup Sortable
 * @class BaseSortContainer
 * @brief Base class for containers of sortable objects
 */
class BaseSortContainer
{
public:
	/// Constructor
	BaseSortContainer()
	{
	}

	/// Destructor
	virtual
	~BaseSortContainer()
	{
	}

	/**
 	 * @name Usual operations for containers
 	 */
	//@{
	virtual void      clear() = 0;
	virtual void      push(Sortable *s) = 0;
	virtual void      pop() = 0;
	virtual void      remove(Sortable *s) = 0;
	virtual Sortable *getTop() const = 0;
	virtual bool      isEmpty() const = 0;
	virtual int       getSize() const = 0;
	//@}
};



/**
 * @ingroup Sortable
 * @class SortQueue
 * @brief Queue of sortables
 */
class SortQueue : public BaseSortContainer
{
public:
	/// Constructor
	SortQueue()
	{
	}

	/// Destructor
	~SortQueue()
	{
		clear();
	}

	/**
 	 * @name Usual operations for containers
 	 */
	//@{
	void      clear();
	void      push(Sortable *s)
	{
		_q.push(s);
	}
	void      pop()
	{
		_q.pop();
	}
	void      remove(Sortable *s)
	{
	}
	Sortable *getTop() const
	{
		return _q.front();
	}
	bool      isEmpty() const
	{
		return _q.empty();
	}
	int       getSize() const
	{
		return _q.size();
	}
	//@}
private:
	std::queue<Sortable *> _q;
};




/**
 * @ingroup Sortable
 * @class SortStack
 * @brief Stack of sortables
 */
class SortStack : public BaseSortContainer
{
public:
	/// Constructor
	SortStack()
	{
	}

	/// Destructor
	~SortStack()
	{
		clear();
	}

	/**
 	 * @name Usual operations for containers
 	 */
	//@{
	void      clear();
	void      push(Sortable *s)
	{
		_s.push(s);
	}
	void      pop()
	{
		_s.pop();
	}
	void      remove(Sortable *s)
	{
	}
	Sortable *getTop() const
	{
		return _s.top();
	}
	bool      isEmpty() const
	{
		return _s.empty();
	}
	int       getSize() const
	{
		return _s.size();
	}
	//@}
private:
	std::stack<Sortable *> _s;
};




/**
 * @ingroup Sortable
 * @class SortSet
 * @brief Set of sortables managing priorities
 */
class SortSet : public BaseSortContainer
{
public:
	/// Constructor
	SortSet()
	{
	}

	/// Destructor
	~SortSet()
	{
		clear();
	}

	/**
 	 * @name Usual operations for containers
 	 */
	//@{
	void      clear()
	{
		_s.clear();
	}
	void      push(Sortable *s)
	{
		_s.insert(s);
	}
	void      pop()
	{
		_s.erase(_s.begin());
	}
	void      remove(Sortable *s)
	{
	}
	Sortable *getTop() const
	{
		return(*(_s.begin()));
	}
	bool      isEmpty() const
	{
		return _s.empty();
	}
	int       getSize() const
	{
		return _s.size();
	}
	//@}
private:
	std::set<Sortable *, SortableComparator> _s;
};


/**
 * @relates elisa::BaseSortContainer
 * @brief Function used to change from container type.
 *
 * The parameter type is the type of the new container.
 * The old one is destroyed after that all sortable objects
 * have been inserted in the new one. A pointer to the new
 * container is returned.
 */
template <class BSC>
BaseSortContainer *
// ishii elisa::muteSortContainer(BaseSortContainer* old)
muteSortContainer(BaseSortContainer *old)
{
	BaseSortContainer *bc;
	if ((bc = dynamic_cast<BSC *>(old)) == 0) {
		BaseSortContainer *newbc = new BSC;
		while (!old->isEmpty()) {
			newbc->push(old->getTop());
			old->pop();
		}
		delete old;
		return newbc;
	} else {
		return old; // old is already of type BSC
	}
}


/**
 * @relates elisa::BaseSortContainer
 * @brief Returns a queue from b
 */
//ishii BaseSortContainer* elisa::muteSortQueue (BaseSortContainer* b);
BaseSortContainer *muteSortQueue(BaseSortContainer *b);


/**
 * @relates elisa::BaseSortContainer
 * @brief Returns a stack from b
 */
// ishii BaseSortContainer* elisa::muteSortStack (BaseSortContainer* b);
BaseSortContainer *muteSortStack(BaseSortContainer *b);


/**
 * @relates elisa::BaseSortContainer
 * @brief Returns a set from b
 */
//ishii BaseSortContainer* elisa::muteSortSet   (BaseSortContainer* b);
BaseSortContainer *muteSortSet(BaseSortContainer *b);


END_NAMESPACE_ELISA


#endif // ELISA_SORTABLE_H
